package storage;

import bean.Contact;
import bean.Term;
import exception.ManchesterQueryException;
import org.coode.owlapi.manchesterowlsyntax.ManchesterOWLSyntaxEditorParser;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.expression.OWLEntityChecker;
import org.semanticweb.owlapi.expression.ParserException;
import org.semanticweb.owlapi.expression.ShortFormEntityChecker;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.owllink.*;
import org.semanticweb.owlapi.owllink.builtin.requests.*;
import org.semanticweb.owlapi.owllink.builtin.response.*;
import org.semanticweb.owlapi.owllink.server.OWLlinkServer;
import org.semanticweb.owlapi.owllink.server.serverfactory.PelletServerFactory;
import org.semanticweb.owlapi.reasoner.Node;
import org.semanticweb.owlapi.util.BidirectionalShortFormProvider;
import org.semanticweb.owlapi.util.BidirectionalShortFormProviderAdapter;
import org.semanticweb.owlapi.util.ShortFormProvider;
import org.semanticweb.owlapi.util.SimpleShortFormProvider;
import util.ConfigHandler;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by IntelliJ IDEA.
 *
 * @author Sarala Wimalaratne
 *         Date: 12-Aug-2011
 *         Time: 08:06:06
 */
public class OwllinkServer {
    public static OwllinkServer owllinkServer = null;
//	public static final String DOCUMENT_IRI = "C:\\Users\\sarala.EBI\\ideaprojects\\restjson\\ws\\web\\WEB-INF\\resources\\ontologies\\ricordo.owl";
    public static final String DOCUMENT_IRI = "/home/sarala/ricordoeu/ricordows/resources/ricordo.owl";
    private static OWLOntologyManager manager = OWLManager.createOWLOntologyManager();

    private static OWLOntology ontology =null;//Create/use an OWLOntology;
    private static OWLlinkReasoner reasoner =null;
    private static String ou = "http://www.ricordo.eu/ricordo.owl";//"http://bioonto.uk/ricordo.owl";
    private static OWLOntology oldOntology =null;//for creating manchester queries
    private static KB kbResponse = null;
    private static IRI docIRI;
    private static OWLlinkReasonerConfiguration reasonerConfiguration = null;
    private static OWLlinkHTTPXMLReasonerFactory factory = null;
    private static OWLlinkServer server = null;
    private static String port = "8081";
    static Logger logger = Logger.getLogger("storage.owllinkServer");

    public OwllinkServer(){
        docIRI=IRI.create(new File(DOCUMENT_IRI));

        try {
            ontology = manager.createOntology();
            oldOntology = manager.loadOntology(docIRI);
        } catch (OWLOntologyCreationException e) {
            e.printStackTrace();
        }

        URL url = null;//Configure the server end-point
        try {
             url = new URL("http://bioonto.gen.cam.ac.uk:"+port);
            //url = new URL("http://localhost:"+port);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        reasonerConfiguration = new OWLlinkReasonerConfiguration(url);
        factory = new OWLlinkHTTPXMLReasonerFactory();
        setUpReasoner();
    }

    public static void setUpReasoner(){
        try{
            reasoner = factory.createNonBufferingReasoner(ontology, reasonerConfiguration);
        }catch (OWLlinkReasonerIOException e){
            System.out.println(e.getMessage());
            startPelletServer();
            reasoner = factory.createNonBufferingReasoner(ontology, reasonerConfiguration);
        }

        createKB();
    }

    public static void createKB(){
        try {
            long st = System.currentTimeMillis();
            CreateKB createKBRequest = new CreateKB(IRI.create(ou));
            kbResponse = reasoner.answer(createKBRequest);
            LoadOntologies loadOntologies = new LoadOntologies(kbResponse.getKB(),IRI.create(new File(DOCUMENT_IRI)));
            OK okResponse = reasoner.answer(loadOntologies);
            logger.info("KB load time: "+(System.currentTimeMillis() - st));
        } catch (OWLlinkErrorResponseException e) {
            logger.log(Level.WARNING,"Problem creating KB",e);
        }
    }

    public static void startPelletServer(){
        PelletServerFactory pellet = new PelletServerFactory();
        server = pellet.createServer(Integer.parseInt(port));
        server.run();
    }

    public void stopPelletServer(){
        if(server!=null) {
            try {
                server.stop();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static Response executeReasoner(Request request){
        Response response = null;
        try{
            long st = System.currentTimeMillis();
            response = reasoner.answer(request);
            logger.info("Query time: " + (System.currentTimeMillis()-st));
        }catch(OWLlinkReasonerIOException ex){
            setUpReasoner();
            executeReasoner(request);
        }
        return response;
    }

    private static OWLClassExpression runManchesterQuery(String manchesterQuery) throws ManchesterQueryException{
        if (owllinkServer == null){
            owllinkServer = new OwllinkServer();
        }
        ManchesterOWLSyntaxEditorParser parser = new ManchesterOWLSyntaxEditorParser(manager.getOWLDataFactory(), manchesterQuery);
        parser.setDefaultOntology(oldOntology);
        ShortFormProvider shortFormProvider = new SimpleShortFormProvider();
        Set<OWLOntology> importsClosure = oldOntology.getImportsClosure();
        BidirectionalShortFormProvider bidiShortFormProvider = new BidirectionalShortFormProviderAdapter(manager, importsClosure, shortFormProvider);
        // Specify an entity checker that wil be used to check a class expression contains the correct names.
        OWLEntityChecker entityChecker = new ShortFormEntityChecker(bidiShortFormProvider);
        parser.setOWLEntityChecker(entityChecker);

        OWLClassExpression classExp=null;
        try {
            classExp = parser.parseClassExpression();
        } catch (ParserException e) {
            e.printStackTrace();
            throw new ManchesterQueryException("Invalid manchester query",e.getMessage());
        }

        if(classExp==null){
            throw new ManchesterQueryException("OWLClassExpression null","OWLClassExpression null");
        }
        return classExp;
    }

    public static ArrayList<Term> getSubTerms(String query) throws ManchesterQueryException {
        OWLClassExpression exp = runManchesterQuery(query);
        return getSubTerms(exp);
    }

    private static ArrayList<Term> getSubTerms(OWLClassExpression classExp){
        ArrayList<Term> idList = new ArrayList<Term>();
        GetSubClasses getSubClasses = new GetSubClasses(IRI.create(ou), classExp);
        SetOfClassSynsets synsets = (SetOfClassSynsets)executeReasoner(getSubClasses); //reasoner.answer(getSubClasses);
        Iterator<Node<OWLClass>> it = synsets.iterator();
        while (it.hasNext()) {
            Node<OWLClass> owlClassNode = it.next();
            idList.add(new Term(owlClassNode.getEntities().iterator().next().toStringID()));
        }
        return idList;
    }

    public static ArrayList<Term> getEquivalentTerms(String query) throws ManchesterQueryException {
        OWLClassExpression exp = runManchesterQuery(query);
        return getEquivalentTerms(exp);
    }

    private static ArrayList<Term> getEquivalentTerms(OWLClassExpression classExp){
        GetEquivalentClasses getEquivalentClasses = new GetEquivalentClasses(IRI.create(ou),classExp);
        SetOfClasses eqclasses = (SetOfClasses)executeReasoner(getEquivalentClasses);//reasoner.answer(getEquivalentClasses);
        ArrayList<Term> idList = new ArrayList<Term>();
        for (Object eqclass : eqclasses) {
            OWLClass eqClass = (OWLClass) eqclass;
            idList.add(new Term(eqClass.toStringID()));
        }
        return idList;
    }

    public static ArrayList<Term> getTerms(String query) throws ManchesterQueryException {
        OWLClassExpression exp = runManchesterQuery(query);
        ArrayList<Term> idList = new ArrayList<Term>();
        idList.addAll(getSubTerms(exp));
        idList.addAll(getEquivalentTerms(exp));
        return idList;
    }

    public static Term addTerm(String query) throws ManchesterQueryException {
        OWLClassExpression exp = runManchesterQuery(query);
        if(getEquivalentTerms(exp).isEmpty()){
            return addTerm(exp);
        }
        else
            return null;
    }

    private static Term addTerm(OWLClassExpression classExp){
        String ricordoid = ConfigHandler.readAndUpdate(ConfigHandler.RICORDOID);
        OWLClass newowlclass = manager.getOWLDataFactory().getOWLClass(IRI.create("http://www.ricordo.eu/ricordo.owl#RICORDO_"+ricordoid));
        OWLAxiom axiom = manager.getOWLDataFactory().getOWLEquivalentClassesAxiom(newowlclass, classExp);
        Set<OWLAxiom> axiomSet = new HashSet<OWLAxiom>();
        axiomSet.add(axiom);
        Tell tellRequest = new Tell(IRI.create(ou),axiomSet);
        OK okResponse = (OK)executeReasoner(tellRequest);//reasoner.answer(tellRequest);

        //add to owlfile
        manager.addAxioms(oldOntology, axiomSet);
        writeToOWLFile();

        return new Term(newowlclass.toStringID());
    }

    private static void writeToOWLFile(){
        try {
            manager.saveOntology(oldOntology, docIRI);
        } catch (OWLOntologyStorageException e) {
            e.printStackTrace();
        }
    }

    /*   public static void main(String [] args){
OwllinkServer owllinkServer = new OwllinkServer();*/
/*        GetAllObjectProperties properties = new GetAllObjectProperties(IRI.create(ou));
        SetOfObjectProperties objectProperties = (SetOfObjectProperties)OwllinkServer.executeReasoner(properties);
         Iterator<OWLObjectProperty> it = objectProperties.iterator();
        while (it.hasNext()) {
            OWLObjectProperty property = it.next();
            System.out.println(property.getIRI());
        }*/
/*

        GetAllClasses classes = new GetAllClasses(IRI.create(ou));
        SetOfClasses setOfClasses = (SetOfClasses)OwllinkServer.executeReasoner(classes);
         Iterator<OWLClass> it = setOfClasses.iterator();
        while (it.hasNext()) {
            OWLClass owlClassNode = it.next();
            System.out.println(owlClassNode.getIRI());
        }
*/

/*        try {

            System.out.println(OwllinkServer.getTerms("PATO_0000117 and inheres-in some FMA_7096").size());
        } catch (ManchesterQueryException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }*/
    //   }

}
